import datetime
import uuid

from conf.neo4j_cnx import NeoCnxPool
from medical_kg.entity_type import entity_view
from web.const import StatusCode

neo_cnx = NeoCnxPool()


class RelSetUp:

    def create_rel(self, rel_name, start_name, end_name, rel_properties_list: list, desc, new_uid=None):
        with neo_cnx.get_session() as session:
            query = (
                'MATCH (n1:EntityType) '
                'MATCH (n2:EntityType) '
                'MATCH (n1)-[rel]->(n2) '
                'WHERE rel.name = $rel_name '
                'RETURN count(rel) as count'
            )
            results = session.run(query, rel_name=rel_name)
            for record in results:
                if record['count'] >= 1:
                    return {'status': StatusCode.REL_SET_UP_REPEATE,
                            'message': ''}
            query = (
                        'MATCH (n1:EntityType {name: $start_name}) '
                        'MATCH (n2:EntityType {name: $end_name}) '
                        'MERGE (n1)-[rel:%s]->(n2) '
                        'ON CREATE SET '
                        'rel.uid = $rel_uid, '
                        'rel.rel_properties_list = $rel_properties_list, '
                        'rel.desc = $desc, '
                        'rel.update_time = datetime(), '
                        'rel.is_abled = $is_abled'
                    ) % rel_name
            new_uid = str(uuid.uuid4()) if new_uid is None else new_uid
            session.run(query, start_name=start_name, end_name=end_name, rel_uid=new_uid,
                        rel_properties_list=rel_properties_list,
                        desc=desc, is_abled=True)

            return {'status': StatusCode.SUCCESS_CODE,
                    'message': ''}

    def update_rel(self, rel_uid, rel_name, start_name, end_name, rel_properties_list: list, desc):
        with neo_cnx.get_session() as session:
            query = (
                'MATCH (n1:EntityType) '
                'MATCH (n2:EntityType) '
                'MATCH (n1)-[rel]->(n2) '
                'WHERE rel.uid = $rel_uid '
                'DELETE rel'
            )
            session.run(query, rel_uid=rel_uid)
            self.create_rel(rel_name, start_name, end_name, rel_properties_list, desc, new_uid=rel_uid)

    def switch_rel_set_up(self, rel_uid, is_abled: bool):
        with neo_cnx.get_session() as session:
            query = (
                'MATCH (n1:EntityType) '
                'MATCH (n2:EntityType) '
                'MATCH (n1)-[rel]->(n2) '
                'WHERE rel.uid = $rel_uid '
                'SET rel.is_abled = $is_abled'
            )
            session.run(query, rel_uid=rel_uid, is_abled=is_abled)

    def query_rel_properties_list(self, rel_name):
        with neo_cnx.get_session() as session:
            query = (
                'MATCH (n1:EntityType) '
                'MATCH (n2:EntityType) '
                'MATCH (n1)-[rel]->(n2) '
                'WHERE type(rel) = $rel_name '
                'RETURN rel.rel_properties_list AS rel_properties_list'
            )
            results = session.run(query, rel_name=rel_name)
            for record in results:
                return record['rel_properties_list']

    def query_rel_list(self, rel_name=None, start_name=None, page_size=10, page_num=1):
        with neo_cnx.get_session() as session:
            rel_list = []
            skip = (page_num - 1) * page_size

            page_sql = (
                           'SKIP %s '
                           'LIMIT %s'
                       ) % (skip, page_size)

            if not rel_name:
                if not start_name:
                    query = (
                                'MATCH (n1:EntityType) '
                                'MATCH (n1)-[rel]->(n2) '
                                'RETURN n1, n2, rel '
                                'ORDER BY rel.update_time DESC '
                            ) + page_sql
                    results = session.run(query)
                else:
                    query = (
                                'MATCH (n1:EntityType) '
                                'MATCH (n1)-[rel]->(n2) '
                                'WHERE n1.name=$start_name '
                                'RETURN n1, n2, rel '
                                'ORDER BY rel.update_time DESC '
                            ) + page_sql
                    results = session.run(query, start_name=start_name)
            else:
                if not start_name:
                    query = (
                                'MATCH (n1:EntityType) '
                                'MATCH (n1)-[rel]->(n2) '
                                'WHERE type(rel) CONTAINS $rel_name, '
                                'RETURN n1, n2, rel '
                                'ORDER BY rel.update_time DESC '
                            ) + page_sql
                    results = session.run(query, rel_name=rel_name)
                else:
                    query = (
                                'MATCH (n1:EntityType) '
                                'MATCH (n1)-[rel]->(n2) '
                                'WHERE type(rel) CONTAINS $rel_name AND n1.name = $start_name '
                                'RETURN n1, n2, rel '
                                'ORDER BY rel.update_time DESC '
                            ) + page_sql
                    results = session.run(query, rel_name=rel_name, start_name=start_name)

            for record in results:
                for i in ['rel']:
                    global_properties = dict(record[i].items())
                    rel_type = record[i].type
                    start_name = record[i].nodes[0].get('name')
                    end_name = record[i].nodes[1].get('name')
                    dt = global_properties['update_time']
                    pdt = datetime.datetime(dt.year, dt.month, dt.day, dt.hour + 8, dt.minute, int(dt.second))

                    rel_list.append({
                        'rel_uid': global_properties['uid'],
                        'rel_name': rel_type,
                        'start_name': entity_view(start_name),
                        'end_name': entity_view(end_name),
                        'rel_properties_list': global_properties['rel_properties_list'],
                        'desc': global_properties['desc'],
                        'update_time': str(pdt),
                        'is_abled': global_properties['is_abled']
                    })

            return rel_list

    def count_all(self):
        with neo_cnx.get_session() as session:
            query = (
                'MATCH (n:EntityType) '
                'MATCH (n)-[rel]->() '
                'RETURN count(rel) AS count'
            )
            results = session.run(query)
            for record in results:
                return record['count']


if __name__ == '__main__':
    rel_set_up_app = RelSetUp()
    rel_set_up_app.create_rel(rel_name='有什么症候', start_name='疾病', end_name='症候',
                              rel_properties_list=[], desc='疾病有哪些症候')
    rel_set_up_app.create_rel(rel_name='有什么影像学检查', start_name='疾病', end_name='影像学检查',
                              rel_properties_list=[], desc='疾病有哪些影像学检查')
    rel_set_up_app.create_rel(rel_name='有什么实验室检查', start_name='疾病', end_name='实验室检查',
                              rel_properties_list=[], desc='疾病有哪些实验室检查')
    rel_set_up_app.create_rel(rel_name='有什么病原体会致病', start_name='疾病', end_name='病原体',
                              rel_properties_list=[], desc='疾病有哪些病原体会致病')
    rel_set_up_app.create_rel(rel_name='有什么治疗方式', start_name='疾病', end_name='治疗方式',
                              rel_properties_list=[], desc='疾病有哪些治疗方式')
    count = rel_set_up_app.count_all()
    results = rel_set_up_app.query_rel_list()
    results = rel_set_up_app.query_rel_properties_list('有什么症候')
